//
// itertool - a polynormial and type-safe iterator framework in C++.
//
// Copyright (c) 2021-2025 Feng Cong
//
// Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at
// https://opensource.org/licenses/MIT

#pragma once

#include <itertool/itertool_fwd.h>

namespace itertool {

using EnumIndexType = size_t;

template <typename T>
struct EnumItem {
  EnumIndexType index;
  T value;

  EnumItem(EnumIndexType idx, T&& val)
      : index(idx), value(std::forward<T>(val)) {}

  template <typename First, typename Second>
  operator std::pair<First, Second>() {
    return std::make_pair(static_cast<First>(index),
                          static_cast<Second>(value));
  }
};

namespace detail {

template <typename T>
using EnumIterableBase = IterableBase<EnumItem<T> /*New*/, T /*Old*/>;

template <typename T>
class EnumIterable : public EnumIterableBase<T> {
 public:
  using ItemType = EnumItem<T>;

  EnumIterable(Iterator<T> it, EnumIndexType start)
      : EnumIterableBase<T>(it), start_(start), index_(start) {}

  ItemType GetNow() override {
    return ItemType(index_, this->BaseGetIterator().GetNow());
  }

  void Advance() override {
    ++index_;
    this->BaseGetIterator().Advance();
  }

  void Reset() override {
    index_ = start_;
    this->BaseGetIterator().Reset();
  }

 private:
  EnumIndexType start_;
  EnumIndexType index_;
};

}  // namespace detail

template <typename T, typename _OldItem = DeclareIterValueType<T>>
auto Enumerate(T&& it, EnumIndexType start = 0)
    -> Iterator<EnumItem<_OldItem>> {
  return MakeIterator<detail::EnumIterable<_OldItem>>(Iter(std::forward<T>(it)),
                                                      start);
}

}  // namespace itertool
